package com.vhly.appspot.twitter;

import com.google.appengine.repackaged.com.google.common.util.Base64;
import com.vhly.appspot.HttpParameter;
import com.vhly.appspot.ResponseData;
import com.vhly.appspot.util.StreamUtil;
import com.vhly.kxmlext.outputer.XMLOutputter;
import org.kxml2.io.KXmlParser;
import org.kxml2.kdom.Document;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.*;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.logging.Logger;

/**
 * Created by IntelliJ IDEA.
 * User: vhly[FR]
 * Date: 2009-11-9
 * Time: 23:34:34
 * Platform: Mac OS X 10.5.8
 *
 * @author vhly[FR]
 */
public final class TwitterClient {

    private static Logger log = Logger.getLogger("TwitterClient");
    private static Mac mac;
    private static Random rnd;

    private static long ctTwitter;

    /**
     * Process Request and return Response
     *
     * @param rd RequestData
     * @return ResponseData
     */
    public static ResponseData processRequest(RequestData rd) {
        ResponseData ret = new ResponseData();
        ret.stateCode = HttpServletResponse.SC_BAD_REQUEST;
        long ct1 = System.currentTimeMillis();
        String uk = genAPICallURL(rd);
        long ct2 = System.currentTimeMillis();
        log.info("get URL:" + (ct2 - ct1));  // 36ms

        URL u;
        int method = rd.httpmethod;
        HttpURLConnection httpConn = null;
        ByteArrayOutputStream bout = null;
        try {
            u = new URL(uk);
            httpConn = (HttpURLConnection) u.openConnection();
            httpConn.setDoInput(true);

            // TODO process auth And set HTTP header
            if (rd.authType == Constants.AUTH_TYPE_BASIC) {
                // 4ms 左右
                byte[] ad = rd.authData;
                if (ad != null && ad.length > 0) {
                    int len = ad.length;
                    for (int i = len - 1; i >= 0; i--) {
                        ad[i] = (byte) (ad[i] ^ i);
                    }
                    httpConn.setRequestProperty("Authorization", "Basic " + Base64.encode(ad));
                } else {
                    throw new IllegalArgumentException("Request AuthType set, but no auth data!");
                }
            } else if (rd.authType == Constants.AUTH_TYPE_OAUTH) {
                // 4ms 左右
                log.info("Gen OAuth");
                List<HttpParameter> oauthParams = makeOAuthParams(rd);
                String sign = genOAuthSign(rd, oauthParams);
                oauthParams.add(new HttpParameter("oauth_signature", sign));
                String as = makeOAuthHeader(oauthParams);
                httpConn.setRequestProperty("Authorization", as);
                log.info("OAuth Header is " + as);

                // TODO 
            }

            // Add User-Agent

            httpConn.setRequestProperty("User-Agent", "TWP/2.0 (GAE; Java;) Tw Proxy 2.0");
            httpConn.setRequestProperty("Accept-Encoding", "gzip");
            httpConn.setRequestProperty("X-Twitter-Client", "TuiTe");
            httpConn.setRequestProperty("X-Twitter-Client-URL", "http://vhlyserver.appspot.com/tw");
            httpConn.setRequestProperty("X-Twitter-Client-Version", "1.7");
            httpConn.setRequestProperty("Connection", "close");

            if (method == Constants.HTTP_API_POST) {
                httpConn.setDoOutput(true);
                httpConn.setRequestMethod("POST");
                httpConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
                List<HttpParameter> pms = rd.params;
                if (pms.size() > 0) {
                    byte[] buf = makePostData(pms);
                    httpConn.setRequestProperty("Content-Length", Integer.toString(buf.length));
                    OutputStream out = httpConn.getOutputStream();
                    out.write(buf);
                    out.close();
                }
//                ct2 = System.currentTimeMillis();
//                log.info("post write " + (ct2 - ct1));     // 6ms
            } else if (method == Constants.HTTP_API_GET) {
                httpConn.setRequestMethod("GET");
            } else if (method == Constants.HTTP_API_DELETE) {
                httpConn.setRequestMethod("DELETE");
            } else if (method == Constants.HTTP_API_HEAD) {
                httpConn.setRequestMethod("HEAD");
            }

            ct1 = System.currentTimeMillis();
            int iv = httpConn.getResponseCode();
            ct2 = System.currentTimeMillis();
            log.info("get Resp Code " + (ct2 - ct1));  // 687ms
            ret.stateCode = iv;
            iv = httpConn.getContentLength();
            ret.contentLength = iv;
            ret.contentEncoding = httpConn.getContentEncoding();
            ret.contentType = httpConn.getContentType();
            InputStream in = httpConn.getInputStream();
            if (iv > 0) {
                ret.data = new byte[iv];
                //noinspection ResultOfMethodCallIgnored
                in.read(ret.data);
            } else {
                bout = new ByteArrayOutputStream();
                StreamUtil.writeStream(in, bout);
                ret.data = bout.toByteArray();
                StreamUtil.close(bout);
            }
            String rateRemaining = httpConn.getHeaderField("x-ratelimit-remaining");
            log.info("Request Method: " + uk);
//            if (rateRemaining != null && rateRemaining.length() < 3) {
            log.warning("RateLimit API: remain:" + rateRemaining);
//            }

            String ctd = httpConn.getHeaderField("X-Ratelimit-Reset");
            if (ctd != null) {
                long cd = Long.parseLong(ctd);
                long cs = System.currentTimeMillis();
                ctTwitter = cd - cs;
            }
            String ct = ret.contentType;
            if (ct != null && ret.data != null && ret.data.length > 0) {
                int index = ct.indexOf(';');
                if (index != -1) {
                    ct = ct.substring(0, index).trim().toLowerCase();
                }
                if (ct.equals("application/xml") || ct.equals("application/atom+xml")) {
                    Document doc = new Document();
                    KXmlParser parser = new KXmlParser();
                    ByteArrayInputStream bin = new ByteArrayInputStream(ret.data);
                    XMLOutputter outputter = new XMLOutputter();
                    try {
                        parser.setInput(bin, "UTF-8");
                        parser.shouldProcessEntity(false);
                        doc.parse(parser);
                        bout = new ByteArrayOutputStream();
                        outputter.output(doc, bout);
                        ret.data = bout.toByteArray();
                    } catch (Exception e) {
                        log.info("error:" + e.getMessage());
                    } finally {
                        outputter = null;
                        parser = null;
                        doc.dealloc();
                        StreamUtil.close(bin);
                        StreamUtil.close(bout);
                    }
                } else {
                    log.info("not xml:" + ct);
                }
            }
        } catch (MalformedURLException e) {
            log.info("EX:" + e);
        } catch (IOException e) {
            log.info("IOE:" + e);
        } catch (Exception e) {
            log.info("EX:" + e);
        } finally {
            StreamUtil.close(bout);
            StreamUtil.close(httpConn);
        }
        return ret;
    }

    public static String makeOAuthHeader(List<HttpParameter> list) throws UnsupportedEncodingException {
        StringBuffer sb = new StringBuffer("OAuth ");
        int size = list.size();
        for (int i = 0; i < size; i++) {
            HttpParameter hp = list.get(i);
            String k = hp.name;
            String v = hp.value;
            sb.append(k).append('=').append('"').append(URLEncoder.encode(v, "UTF-8")).append('"');
            if (i < size - 1) {
                sb.append(", ");
            }
        }
        return sb.toString();
    }

    public static String genOAuthSign(RequestData rd, List<HttpParameter> oauthParams) {
        String ret = "";
        String secret = rd.getConsumerSecret();
        StringBuffer sb = new StringBuffer();

        switch (rd.httpmethod) {
            case Constants.HTTP_API_GET:
                sb.append("GET");
                break;
            case Constants.HTTP_API_POST:
                sb.append("POST");
                break;
            case Constants.HTTP_API_HEAD:
                sb.append("HEAD");
                break;
            case Constants.HTTP_API_DELETE:
                sb.append("DELETE");
                break;
        }
        sb.append('&');
        String uk = genAPICallURL(rd);
        URL url = null;
        try {
            url = new URL(uk);
            StringBuffer sb1 = new StringBuffer();
            sb1.append(url.getProtocol()).append("://").append(url.getHost());
            int port = url.getPort();
            if (port > 0) {
                sb1.append(':').append(port);
            }
            sb1.append(url.getFile());
            String base = sb1.toString();
            sb.append(URLEncoder.encode(base, "UTF-8")).append('&');
            // TODO Add OAuth Param
            int len = oauthParams.size();

            // TODO Add HTTP Parameters
            List<HttpParameter> baseParams = new ArrayList<HttpParameter>(len + rd.params.size());
            baseParams.addAll(oauthParams);
            baseParams.addAll(rd.params);
            parseGetParameters(uk,baseParams);
            Collections.sort(baseParams);
            int size = baseParams.size();
            for(int i = 0;i<size;i++){
                HttpParameter hp = baseParams.get(i);
                sb.append(URLEncoder.encode(hp.name,"UTF-8")).append("%3D").append(URLEncoder.encode(hp.value,"UTF-8"));
                if(i < size - 1){
                    sb.append("%26");
                }
            }
            String data = sb.toString();
            log.info(data);
            String tks1 = rd.getTokenSecret();
            if (tks1 == null) {
                tks1 = "";
            }
            String sc = secret + "&" + tks1;
            ret = getHmacSha1(data.getBytes("UTF-8"), sc.getBytes("UTF-8"));
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return ret;
    }

    private static void parseGetParameters(String url, List<HttpParameter> signatureBaseParams) {
        int queryStart = url.indexOf("?");
        if (-1 != queryStart) {
            String[] queryStrs = url.substring(queryStart + 1).split("&");
            try {
                for (String query : queryStrs) {
                    String[] split = query.split("=");
                    if (split.length == 2) {
                        signatureBaseParams.add(
                                new HttpParameter(URLDecoder.decode(split[0],
                                        "UTF-8"), URLDecoder.decode(split[1],
                                        "UTF-8")));
                    } else {
                        signatureBaseParams.add(
                                new HttpParameter(URLDecoder.decode(split[0],
                                        "UTF-8"), ""));
                    }
                }
            } catch (UnsupportedEncodingException ignore) {
            }

        }

    }

    public static List<HttpParameter> makeOAuthParams(RequestData rd) {
        List<HttpParameter> oauthParams = new ArrayList<HttpParameter>();
        oauthParams.add(new HttpParameter("oauth_consumer_key", rd.getConsumerKey()));
        oauthParams.add(new HttpParameter("oauth_signature_method", "HMAC-SHA1"));
        long ts = System.currentTimeMillis() / 1000;
        oauthParams.add(new HttpParameter("oauth_timestamp", Long.toString(ts)));
        oauthParams.add(new HttpParameter("oauth_nonce", Long.toString(ts + 23783)));
        oauthParams.add(new HttpParameter("oauth_version", "1.0"));
        String tk = rd.getToken();
        String tks = rd.getTokenSecret();
        if (tk != null && tks != null) {
            oauthParams.add(new HttpParameter("oauth_token", tk));
        }
        return oauthParams;
    }

    public static byte[] makePostData(List<HttpParameter> pms) {
        String uk;
        StringBuffer sb = new StringBuffer();
        int size = pms.size();
        String v;
        try {
            for (int i = 0; i < size; i++) {
                HttpParameter hp = pms.get(i);
                uk = hp.name;
                v = hp.value;
                sb.append(URLEncoder.encode(uk, "UTF-8")).append("=").append(URLEncoder.encode(v, "UTF-8"));
                if (i < size - 1) {
                    sb.append('&');
                }
            }
        } catch (UnsupportedEncodingException uee) {
            uee.printStackTrace();
        }
        v = sb.toString();
        byte[] ret = null;
        try {
            ret = v.getBytes("UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return ret;
    }

    /**
     * Get response Format type
     *
     * @param format type
     * @return Response Format Type Name
     */
    private static String getFormatByType(int format) {
        String ret = "";
        switch (format) {
            case Constants.FORMAT_TYPE_XML:
                ret = ".xml";
                break;
            case Constants.FORMAT_TYPE_JSON:
                ret = ".json";
                break;
            case Constants.FORMAT_TYPE_RSS:
                ret = ".rss";
                break;
            case Constants.FORMAT_TYPE_ATOM:
                ret = ".atom";
                break;
        }
        return ret;
    }

    /**
     * Get API method String according category and method
     *
     * @param ca Category
     * @param md method
     * @return API URL
     */
    private static String getAPIMethod(int ca, int md) {
        String ret = "";
        switch (ca) {
            case Constants.CATEGORY_STATUS:
                ret = getStatusesMethod(md);
                break;
            case Constants.CATEGORY_USERS:
                if (md == Constants.METHOD_USERS_SHOW) {
                    ret = "/show";
                } else if (md == Constants.METHOD_USERS_SEARCH) {
                    // TODO none other method [2009/11/11]
                    ret = "/search";
                }
                break;
            case Constants.CATEGORY_SOCIAL_GRAPH:
                if (md == Constants.METHOD_FRIENDS_IDS) {
                    ret = "/friends/ids";
                } else {
                    ret = "/followers/ids";
                }
                break;
            case Constants.CATEGORY_DIRECT_MESSAGES:
                ret = getDirectMessageMethod(md);
                break;
            case Constants.CATEGORY_FRIENDSHIPS:
                if (md == Constants.METHOD_FRIENDSHIP_CREATE) {
                    ret = "/create";
                } else if (md == Constants.METHOD_FRIENDSHIP_DESTROY) {
                    ret = "/destroy";
                } else if (md == Constants.METHOD_FRIENDSHIP_EXISTS) {
                    ret = "/exists";
                } else if (md == Constants.METHOD_FRIENDSHIP_SHOW) {
                    ret = "/show";
                }
                break;
            case Constants.CATEGORY_ACCOUNT:
                ret = getAccountMethod(md);
                break;
            case Constants.CATEGORY_FAVORITE:
                if (md == Constants.METHOD_FAVORITES_CREATE) {
                    ret = "/create";
                } else if (md == Constants.METHOD_FAVORITES_DESTROY) {
                    ret = "/destroy";
                }
                break;
            case Constants.CATEGORY_NOTIFICATION:
                if (md == Constants.METHOD_NOTIFICATIONS_FOLLOW) {
                    ret = "/follow";
                } else if (md == Constants.METHOD_NOTIFICATIONS_LEAVE) {
                    ret = "/leave";
                }
                break;
            case Constants.CATEGORY_BLOCKS:
                if (md == Constants.METHOD_BLOCKS_CREATE) {
                    ret = "/create";
                } else if (md == Constants.METHOD_BLOCKS_DESTROY) {
                    ret = "/destroy";
                } else if (md == Constants.METHOD_BLOCKS_EXISTS) {
                    ret = "/exists";
                } else if (md == Constants.METHOD_BLOCKS_BLOCKING) {
                    ret = "/blocking";
                } else if (md == Constants.METHOD_BLOCKS_BLOCKING_IDS) {
                    ret = "/blocking/ids";
                }
                break;
            case Constants.CATEGORY_HELP:
                if (md == Constants.METHOD_HELP_TEST) {
                    ret = "/test";
                }
                break;
            case Constants.CATEGORY_OAUTH:
                ret = getOAuthMethod(md);
                break;
            case Constants.CATEGORY_SAVED_SEARCH:
                ret = getSavedSearchMethod(md);
                break;
        }
        return ret;
    }

    private static String getSavedSearchMethod(int md) {
        String ret = "";
        switch (md) {
            case Constants.METHOD_SAVED_SEARCH:
                break;
            case Constants.METHOD_SAVED_SEARCH_SHOW:
                ret = "/show";
                break;
            case Constants.METHOD_SAVED_SEARCH_CREATE:
                ret = "/create";
                break;
            case Constants.METHOD_SAVED_SEARCH_DESTROY:
                ret = "/destroy";
                break;
        }
        return ret;
    }

    /**
     * get OAuth Method Name
     *
     * @param md Method Code
     * @return Name
     */
    private static String getOAuthMethod(int md) {
        String ret = "";
        switch (md) {
            case Constants.METHOD_OAUTH_REQUEST_TOKEN:
                ret = "/request_token";
                break;
            case Constants.METHOD_OAUTH_AUTHORIZE:
                ret = "/authorize";
                break;
            case Constants.METHOD_OAUTH_AUTHENTICATE:
                ret = "/authenticate";
                break;
            case Constants.METHOD_OAUTH_ACCESS_TOKEN:
                ret = "/access_token";
                break;

        }
        return ret;
    }

    /**
     * Get Account Method
     *
     * @param md account method typecode
     * @return method name
     */
    private static String getAccountMethod(int md) {
        String ret = "";
        switch (md) {
            case Constants.METHOD_ACCOUNT_END_SESSION:
                ret = "/end_session";
                break;
            case Constants.METHOD_ACCOUNT_RATE_LIMIT_STATUS:
                ret = "/rate_limit_status";
                break;
            case Constants.METHOD_ACCOUNT_UPDATE_DELIVERY_DEVICE:
                ret = "/update_delivery_device";
                break;
            case Constants.METHOD_ACCOUNT_UPDATE_LOCATION:
                ret = "/update_location";
                break;
            case Constants.METHOD_ACCOUNT_UPDATE_PROFILE:
                ret = "/update_profile";
                break;
            case Constants.METHOD_ACCOUNT_UPDATE_PROFILE_BACKGROUND_IMAGE:
                ret = "/update_profile_background_image";
                break;
            case Constants.METHOD_ACCOUNT_UPDATE_PROFILE_COLORS:
                ret = "/update_profile_colors";
                break;
            case Constants.METHOD_ACCOUNT_UPDATE_PROFILE_IMAGE:
                ret = "/update_profile_image";
                break;
            case Constants.METHOD_ACCOUNT_VERIFY_CREDENTIALS:
                ret = "/verify_credentials";
                break;
        }
        return ret;
    }

    /**
     * get DM Method
     *
     * @param md Method Code
     * @return Name
     */
    private static String getDirectMessageMethod(int md) {
        String ret = "";
        switch (md) {
            case Constants.METHOD_DIRECT_MESSAGES:
                break;
            case Constants.METHOD_DIRECT_MESSAGES_DESTROY:
                ret = "/destroy";
                break;
            case Constants.METHOD_DIRECT_MESSAGES_NEW:
                ret = "/new";
                break;
            case Constants.METHOD_DIRECT_MESSAGES_SENT:
                ret = "/sent";
                break;
        }
        return ret;
    }

    /**
     * get statuses 's method names
     *
     * @param md method code
     * @return Name
     */
    private static String getStatusesMethod(int md) {
        String ret = "";
        switch (md) {
            case Constants.METHOD_STATUSES_DESTORY:
                ret = "/destroy";
                break;
            case Constants.METHOD_STATUSES_FOLLOWERS:
                ret = "/followers";
                break;
            case Constants.METHOD_STATUSES_FRIENDS:
                ret = "/friends";
                break;
            case Constants.METHOD_STATUSES_FRIENDS_TIMELINE:
                ret = "/friends_timeline";
                break;
            case Constants.METHOD_STATUSES_PUBLIC_TIMELINE:
                ret = "/public_timeline";
                break;
            case Constants.METHOD_STATUSES_REPLIES:
                ret = "/replies";
                break;
            case Constants.METHOD_STATUSES_SHOW:
                ret = "/show";
                break;
            case Constants.METHOD_STATUSES_UPDATE:
                ret = "/update";
                break;
            case Constants.METHOD_STATUSES_USER_TIMELINE:
                ret = "/user_timeline";
                break;
            // Come soon
            case Constants.METHOD_STATUSES_HOME_TIMELINE:
                ret = "/home_timeline";
                break;
            case Constants.METHOD_STATUSES_RETWEETED_BY_ME:
                ret = "/retweeted_by_me";
                break;
            case Constants.METHOD_STATUSES_RETWEETED_TO_ME:
                ret = "/retweeted_to_me";
                break;
            case Constants.METHOD_STATUSES_RETWEETS_OF_ME:
                ret = "/retweets_of_me";
                break;
            case Constants.METHOD_STATUSES_RETWEET:
                ret = "/retweet";
                break;
            case Constants.METHOD_STATUSES_RETWEETS:
                ret = "/retweets";
                break;
            case Constants.METHOD_STATUSES_MENTIONS:
                ret = "/mentions";
                break;
        }
        return ret;
    }

//    private static boolean needAuth(int code) {
//        if (code == (Constants.METHOD_STATUSES_PUBLIC_TIMELINE)) {
//            return false;
//        } else if (code == (Constants.CATEGORY_ACCOUNT << 4 | Constants.METHOD_ACCOUNT_RATE_LIMIT_STATUS)) {
//            return false;
//        } else if (code == (Constants.CATEGORY_HELP << 4 | Constants.METHOD_HELP_TEST)) {
//            return false;
//        }
//        return true;
//    }

    public static String genAPICallURL(RequestData rd) {
        int ca = rd.category;
        int md = rd.method;
        List<HttpParameter> args = rd.params;
        int httpMethod = rd.httpmethod;
        int hasID = rd.hasIDSet;
        String ret;
        StringBuffer sb = new StringBuffer();
        if (ca == Constants.CATEGORY_SEARCH) {
            sb.append(Constants.twitterSearchServer);
            if (md == Constants.METHOD_SEARCH_KEYWORD) {
                // search  format json atom
                sb.append("/search");
            } else if (md == Constants.METHOD_SEARCH_TREND) {
                sb.append("/trends");
            } else if (md == Constants.METHOD_SEARCH_TREND_CURRENT) {
                sb.append("/trends/current");
            } else if (md == Constants.METHOD_SEARCH_TREND_DAILY) {
                sb.append("/trends/daily");
            } else if (md == Constants.METHOD_SEARCH_TREND_WEEKLY) {
                sb.append("/trends/weekly");
            }
            // TODO process search's API
        } else {
//            if (rd.authType == Constants.AUTH_TYPE_OAUTH) {
//                sb.append(Constants.httpsAPIServer);
//            } else {
            sb.append(Constants.twitterAPIServer);
//            }
            if (ca == Constants.CATEGORY_USER_LIST) {
                // TODO process userid/list API
//                String user = args.get("tt_user");
//                sb.append('/').append(user);
//                args.remove("tt_user");
                int index = indexOfByKey(args, "tt_user");
                if (index != -1) {
                    HttpParameter hp = args.get(index);
                    if (hp != null) {
                        String aid = hp.value;
                        sb.append('/').append(aid);
                    }
                    args.remove(index);
                }
            }
            String[] cas = Constants.categories;
            if (ca < cas.length) {
                sb.append(cas[ca]);
            }
            sb.append(getAPIMethod(ca, md));
            if (hasID != 0) {
//                String aid = args.get("tt_id");
                int index = indexOfByKey(args, "tt_id");
                if (index != -1) {
                    HttpParameter hp = args.get(index);
                    if (hp != null) {
                        String aid = hp.value;
                        sb.append('/').append(aid);
                    }
                    args.remove(index);
                }
            }
        }
        String frm = getFormatByType(rd.format);
        sb.append(frm);
        if (httpMethod == Constants.HTTP_API_GET) {
            int as = args.size();
            if (as > 0) {
                sb.append('?');
//                Enumeration<String> keys = args.keys();
                String k, v;
                try {
                    for (int i = 0; i < as; i++) {
                        HttpParameter hp = args.get(i);
                        k = hp.name;
                        v = hp.value;
                        sb.append(URLEncoder.encode(k, "UTF-8")).append('=').append(URLEncoder.encode(v, "UTF-8"));
                        if (i < as - 1) {
                            sb.append('&');
                        }
                    }
                } catch (UnsupportedEncodingException uee) {
                    uee.printStackTrace();
                }
            }
        }
        ret = sb.toString();
        return ret;
    }

    public static int indexOfByKey(List<HttpParameter> list, String key) {
        int ret = -1;
        if (list != null && key != null) {
            int size = list.size();
            for (int i = 0; i < size; i++) {
                HttpParameter hp = list.get(i);
                if (hp.name.equals(key)) {
                    ret = i;
                    break;
                }
            }
        }
        return ret;
    }


//    /**
//     *
//     *
//     * @param code category[method]
//     * @return HTTP Method
//     */
//    private static int getMethodHTTPMethod(int code) {
//        int ret = Constants.HTTP_API_GET;
//        String s = Integer.toString(code);
//        if (postlookup.contains(s)) {
//            ret = Constants.HTTP_API_POST;
//        } else if (getlookup.contains(s)) {
//            ret = Constants.HTTP_API_GET;
//        } else {
//            int count = postcalls.length;
//            int c;
//            for (int i = 0; i < count; i++) {
//                c = postcalls[i];
//                if (c == code) {
//                    postlookup.add(Integer.toString(code));
//                    ret = Constants.HTTP_API_POST;
//                    break;
//                }
//            }
//            if (ret == Constants.HTTP_API_GET) {
//                getlookup.add(Integer.toString(code));
//            }
//        }
//        return ret;
//    }

    // ---------- OAuth Support ---------------

    /*
    1. OAuth need Signing Requests
         1) make request data
            httpMethod + "&" url_encode(  base_uri ) + "&" +
            sorted_query_params.each  { | k, v |
                url_encode ( k ) + "%3D" + url_encode ( v )
            }.join("%26")
         2) Twitter requires that all OAuth requests be signed using the HMAC-SHA1 algorithm.
    2. Acquiring a request token
         1) Twitter's end point for the request token step is http://api.twitter.com/oauth/request_token.
         2) You should use the POST HTTP method when using this end point. SSL is recommended.
         

     */


    /**
     * @param data 待加密的数据
     * @param key  加密使用的key
     * @return Base64编码的String
     */
    private static String getHmacSha1(byte[] data, byte[] key) {
        SecretKeySpec signingKey = new SecretKeySpec(key, "HmacSHA1");
        try {
            if (mac == null) {
                mac = Mac.getInstance("HmacSHA1");
            }
            mac.init(signingKey);
        }
        catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
        catch (InvalidKeyException e) {
            throw new RuntimeException(e);
        }
        byte[] rawHmac = mac.doFinal(data);
        mac.reset();
        return Base64.encode(rawHmac);
    }

    // ---------- OAuth Support End ---------------


}
